<?php

use Medoo\Medoo;


/**
 *
 * @method static array select($join = null, $columns = null, $where = null)
 * @method static mixed get($join = null, $columns = null, $where = null)
 * @method static int count($join = null, $column = null, $where = null)
 * @method static bool has($join, $where = null)
 * @method static string max($join, $column = null, $where = null)
 * @method static string min($join, $column = null, $where = null)
 * @method static string sum($join, $column = null, $where = null)
 * @method static string avg($join, $column = null, $where = null)
 * @method static array rand($join, $column = null, $where = null)
 * @method static void action(callable $actions)
 * @method static PDOStatement insert(array $values, string $primaryKey = null)
 * @method static PDOStatement update(array $data, array $where = null)
 * @method static PDOStatement delete(array $where = null)
 * @method static string id(string $name = null)
 * @method static array log()
 * @method static string last()
 */
class CoreDbMySQL
{
    const _CONFIG_FILE_ = 'db.memory';

    const _CONFIG_SECTION_ = 'common';

    const _CONFIG_FUN_LIST_ = [
        'select','get','count','has','max','min','sum','avg','rand','insert','update','delete'
    ];

    use CoreTraitSingleton;

    /**
     * @throws Exception
     */
    public static function instance($file, $section, $database = ''): Medoo
    {
        $conf = IniReaderDb::getConfig($file, $section);
        if ($database) $conf->database = $database;
        return new Medoo((array)$conf + ['logging' => true]);
    }

    /**
     * @throws Exception
     */
    public static function iniReaderDb(): IniReaderDb
    {
        extract(self::handleAttributes(), EXTR_OVERWRITE);
        $conf = self::getSingle("$file|$section", [IniReaderDb::class, 'getConfig'], $file, $section);
        extract(self::parseModelFile(), EXTR_OVERWRITE);
        if ($database) $conf->database = $database;
        return $conf;
    }

    /**
     * @throws ReflectionException
     */
    public static function parseModelFile(): array
    {
        $reflection = CoreReflection::getInstance(static::class);
        //M开头的文件是数据模型
        $filename = substr($reflection->getShortName(), 1);
        //第一个单词是库名称,其余部分是表名
        $separator = '_';
        $full = uncamelize($filename, $separator);
        $arr = explode($separator, $full);
        $database = array_shift($arr);
        $tableName = implode($separator, $arr);
        return compact('database', 'tableName');
    }

    /**
     * @throws ReflectionException
     */
    private static function handleAttributes(): array
    {
        list($file, $section) = [static::_CONFIG_FILE_, static::_CONFIG_SECTION_];
        $errorHandler = null;
        $reflection = CoreReflection::getInstance(static::class);
        $iniReaderDb = true;
        $errorHandlerDb = true;

        //解析当前类和父类的注解
        foreach ([$reflection->getAttributes(), $reflection->getParentClass()->getAttributes()] as $attributes) {
            foreach ($attributes as $attribute) {
                $instance = $attribute->newInstance();
                //根据不同的注解处理对应问题
                if ($iniReaderDb && $instance instanceof AttributeIniReader) {
                    extract($attribute->getArguments(), EXTR_OVERWRITE);
                    $iniReaderDb = false;
                    continue;
                }
                if ($errorHandlerDb && $instance instanceof AttributeErrorHandlerDb) {
                    $errorHandler = $instance->getHandler();
                    $errorHandlerDb = false;
                    continue;
                }
            }
        }
        return compact('file', 'section', 'errorHandler');
    }

    public static function __callStatic($name, $arguments)
    {
        try {

            extract(self::handleAttributes(), EXTR_OVERWRITE);

            extract(self::parseModelFile(), EXTR_OVERWRITE);//database tableName

            /**
             * @var Medoo $instance
            */
            $instance = self::getSingle("$file|$section|$database", [self::class, 'instance'], $file, $section, $database);

            if (in_array($name, static::_CONFIG_FUN_LIST_)) array_unshift($arguments, $tableName);

            return $instance->{$name}(...$arguments);

        } catch (\Exception $e) {
            $sql = '';
            if (isset($instance) && $instance instanceof Medoo) $sql = $instance->last();

            $message = ['sql' => $sql, 'msg' => $e->getMessage()];

            if (isset($errorHandler)) $errorHandler::errorHandler(new Exception(json_encode($message, JSON_UNESCAPED_UNICODE)));

            return false;
        }
    }
}